#pragma once
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <vector>
#include <time.h>
using std::cout;
using std::endl;

template <class T>
class RingQueue
{
    static const int Default = 10;
    void P(sem_t&sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t&sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void Unlock(pthread_mutex_t mutex)
    {
        pthread_mutex_unlock(&mutex);   
    }
public:
    RingQueue(int defaultnum = Default)
        : _v(defaultnum),_cap(defaultnum),_c_step(0),_p_step(0)
    {
        sem_init(&SpaceSem, 0, _cap);
        sem_init(&DataSem, 0, 0);

        pthread_mutex_init(&p_mutex,nullptr);
        pthread_mutex_init(&c_mutex,nullptr);
    }
    ~RingQueue()
    {
        sem_destroy(&SpaceSem);
        sem_destroy(&DataSem);
        pthread_mutex_destroy(&c_mutex);
        pthread_mutex_destroy(&p_mutex);
    }
    void Push(const T& data)
    {
        P(SpaceSem); //信号量资源不需要被保护,临界区代码要尽可能少
        Lock(p_mutex);//效率更高
        _v[_p_step] = data;
        _p_step++;
        _p_step %= Default;
        Unlock(p_mutex);
        V(DataSem);
    }
    void Pop(T* out) //输出型参数
    {
       P(DataSem);
       Lock(c_mutex);
       *out = _v[_c_step];
       _c_step++;
       _c_step %= Default;
       V(SpaceSem);
       Unlock(c_mutex);
    }
private:
    sem_t SpaceSem;
    sem_t DataSem;
    std::vector<T> _v;
    int _cap;
    int _c_step; // 消费者下标;
    int _p_step;  // 生产者下标

    pthread_mutex_t c_mutex;
    pthread_mutex_t p_mutex;
};
